package com.example.leetcode.c1_c100.c99;
/**
 * 二叉搜索树中的两个节点被错误地交换。
 *
 * 请在不改变其结构的情况下，恢复这棵树。
 *
 * 示例 1:
 *
 * 输入: [1,3,null,null,2]
 *
 *    1
 *   /
 *  3
 *   \
 *    2
 *
 * 输出: [3,1,null,null,2]
 *
 *    3
 *   /
 *  1
 *   \
 *    2
 * 示例 2:
 *
 * 输入: [3,1,4,null,null,2]
 *
 *   3
 *  / \
 * 1   4
 *    /
 *   2
 *
 * 输出: [2,1,4,null,null,3]
 *
 *   2
 *  / \
 * 1   4
 *    /
 *   3
 * 进阶:
 *
 * 使用 O(n) 空间复杂度的解法很容易实现。
 * 你能想出一个只使用常数空间的解决方案吗？
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/recover-binary-search-tree
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */

import com.example.leetcode.common.TreeNode;
import com.example.leetcode.common.TreeNodeWrapper;

import java.util.ArrayList;
import java.util.List;

/**
 * 恢复二叉搜索树
 * @author zhanpengguo
 * @date 2020-09-30 13:34
 */
public class Solution {

    private List<Integer> list = new ArrayList<>();
    private int count = -1;

    public void recoverTree(TreeNode root) {
        // 二叉搜索树，中序遍历后是一个升序数组
        // 如果交换的两个元素不相邻，则结果会有两个不符合升序的位置，x和y
        // 如果交换的两个元素相邻，则结果只有一个不符合升序的位置，x和x+1
        int x = -1;
        int y = -1;
        middleOrder(root);
        for (int i = 0; i < list.size(); i++) {
            if (i > 0 && list.get(i) < list.get(i - 1)) {
                if (x == -1) {
                    x = i - 1;
                } else {
                    y = i;
                }
            }
        }
        if (y == -1) {
            y = x + 1;
        }
        // 交换x和y的值
        swap(root, x, y);
    }

    private void middleOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        middleOrder(root.left);
        list.add(root.val);
        middleOrder(root.right);
    }

    private void swap(TreeNode root, int x, int y) {
        if (root == null) {
            return;
        }
        swap(root.left, x, y);
        count++;
        if (count == x) {
            root.val = list.get(y);
        } else if (count == y) {
            root.val = list.get(x);
        }
        swap(root.right, x, y);
    }


    public static void main(String[] args) {
        TreeNode root = TreeNodeWrapper.stringToTreeNode("[3,1,4,null,null,2]");
        TreeNodeWrapper.prettyPrintTree(root);
        System.out.println();
        Solution solution = new Solution();
        solution.recoverTree(root);
        TreeNodeWrapper.prettyPrintTree(root);
    }
}
